package com.flow.asyncflow.core.utils.log.asyncflowlog;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.flow.asyncflow.core.entity.config.AsyncFlowInfo;
import com.flow.asyncflow.core.entity.core.AsyncFlowBaseContext;
import com.flow.asyncflow.core.entity.core.AsyncFlowNodeResponse;
import com.flow.asyncflow.core.entity.core.AsyncFlowRequest;
import com.flow.asyncflow.core.entity.log.asyncflowlog.AsyncFlowExecutionMethodEntity;
import com.flow.asyncflow.core.entity.log.asyncflowlog.AsyncFlowLogEntity;
import com.flow.asyncflow.core.entity.log.asyncflowlog.AsyncFlowNodeDetailLogEntity;
import com.flow.asyncflow.core.entity.log.asyncflowlog.AsyncFlowNodeLogEntity;
import com.flow.asyncflow.core.enums.ExecuteEnum;
import com.flow.asyncflow.core.utils.common.UtilsCommon;
import com.flow.asyncflow.core.utils.mongodb.MongoHelper;
import com.flow.asyncflow.core.utils.msg.AsyncFlowSendMsg;
import org.apache.commons.lang.StringUtils;
import org.bson.Document;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

public class AsyncFlowCommon_Log {


    //region 添加操作节点执行日志

    /**
     * 执行过程中添加操作节点执行日志
     *
     * @param request               请求参数
     * @param asyncFlowNodeResponse 返回参数
     * @param asyncData             上下文
     * @param obj                   执行体
     * @param startTime             开始执行时间
     * @param executeEnum           日志类型 1：验证   2：查询  3：操作   4：保存    5：保存后同步    6：保存后异步
     * @param isAsync               方法运行方式 是否异步
     */
    public static void AddAsyncFlowLog(AsyncFlowRequest request, AsyncFlowNodeResponse asyncFlowNodeResponse, AsyncFlowBaseContext asyncData, Object obj, Date startTime, ExecuteEnum executeEnum, boolean isAsync) {
        //节点内部标记不记录当前节点的轨迹日志
        if (asyncFlowNodeResponse.isIgnoreNodeTrackLog()
                || (asyncData.getAsyncFlowInfo().getIgnoreFlowLogEvn().contains(asyncData.getAsyncFlowInfo().getEvn()))) {
            return;
        }
        AsyncFlowExecutionMethodEntity asyncFlowExecutionMethodEntity = UtilsCommon.getLogMethodName(obj);
        AsyncFlowNodeLogEntity asyncFlowLog = new AsyncFlowNodeLogEntity();
        asyncFlowLog.setBusinessSerialId(request.getBusinessSerialId());
        asyncFlowLog.setAsyncFlowModuleEnum(request.getReqTypeEnumName());
        asyncFlowLog.setAsyncFlowNodeEnum(request.getReqTypeEnumMsg());
        asyncFlowLog.setLogMethodName(asyncFlowExecutionMethodEntity.getLogMethodName());
        asyncFlowLog.setLogFileName(asyncFlowExecutionMethodEntity.getMethodSimpleName());
        asyncFlowLog.setLogNodePath(asyncFlowExecutionMethodEntity.getMethodName());
        asyncFlowLog.setLogMsg(asyncFlowNodeResponse.getMsg());
        if (asyncData.getAsyncFlowInfo().getEvn().equals("test")) {
            asyncFlowLog.setLogTime(LocalDateTime.now());
        } else {
            asyncFlowLog.setLogTime(LocalDateTime.now().minusHours(8));
        }

        asyncFlowLog.setCode(asyncFlowNodeResponse.getCode());
        asyncFlowLog.setAsync(isAsync);
        Long time = new Date().getTime() - startTime.getTime();
        asyncFlowLog.setUseTimes(time);
        asyncFlowLog.setExecuteEnumCode(executeEnum.getCode());
        //TODO 为了eorderservice做版本升级的临时处理，升级完成之后可以删除这个特殊处理
        String asyncFlowLogName = asyncFlowLog.getLogFileName();
        if (asyncFlowLogName.contains("_1_")) {
            asyncFlowLogName = asyncFlowLogName.replace("_1_", "");
        }
        String finalAsyncFlowLogName = asyncFlowLogName;
        List<AsyncFlowNodeDetailLogEntity> asyncFlowNodeDetailLogEntityList =
                asyncData.getAsyncFlowNodeDetailLogEntityList().stream().filter(c -> c.getLogFileName().equals(finalAsyncFlowLogName)).collect(Collectors.toList());
        asyncData.getAsyncFlowNodeDetailLogEntityList().removeAll(asyncFlowNodeDetailLogEntityList);

        if (asyncFlowNodeDetailLogEntityList.size() > 0) {
            asyncFlowLog.getAsyncFlowNodeDetailLogEntityList().addAll(0, asyncFlowNodeDetailLogEntityList);
        }
        asyncData.getAsyncFlowNodeLogEntityList().add(asyncFlowLog);
    }
    //endregion

    //region 插入节点明细日志

    /**
     * 插入节点明细日志
     *
     * @param asyncData     上下文
     * @param logFileName   文件名称
     * @param LogDetailName 日志名称
     * @param request       请求
     * @param response      返回
     * @param status        状态
     */
    public static void AddAsyncFlowDetailLog(AsyncFlowBaseContext asyncData, String logFileName, String LogDetailName, Object request, Object response, boolean status) {
        if (asyncData.getAsyncFlowInfo().getIgnoreFlowLogEvn().contains(asyncData.getAsyncFlowInfo().getEvn())) {
            return;
        }
        AsyncFlowNodeDetailLogEntity asyncFlowLogDetailEntity = new AsyncFlowNodeDetailLogEntity();
        //日志所在文件类名称
        asyncFlowLogDetailEntity.setLogFileName(logFileName);
        asyncFlowLogDetailEntity.setLogDetailName(LogDetailName);
        String reqLog = "";
        String resLog = "";
        if (request != null) {
            if (request instanceof String) {
                reqLog = (String) request;
            } else {
                reqLog = JSON.toJSONString(request, SerializerFeature.DisableCircularReferenceDetect);
            }

        }
        if (response != null) {
            if (response instanceof String) {
                resLog = (String) response;
            } else {
                resLog = JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect);
            }

        }
        asyncFlowLogDetailEntity.setRequest(reqLog);
        asyncFlowLogDetailEntity.setResponse(resLog);
        asyncFlowLogDetailEntity.setStatus(status);
        asyncData.getAsyncFlowNodeDetailLogEntityList().add(asyncFlowLogDetailEntity);
    }


//    public static void AddAsyncFlowDetailLog(AsyncFlowNodeResponse asyncFlowNodeResponse, String logFileName, String LogDetailName, Object request, Object response, boolean status) {
//
//        AsyncFlowNodeDetailLogEntity asyncFlowLogDetailEntity = new AsyncFlowNodeDetailLogEntity();
//        //日志所在文件类名称
//        asyncFlowLogDetailEntity.setLogFileName(logFileName);
//        asyncFlowLogDetailEntity.setLogDetailName(LogDetailName);
//        String reqLog = "";
//        String resLog = "";
//        if (request != null) {
//            reqLog = JSON.toJSONString(request, SerializerFeature.DisableCircularReferenceDetect);
//        }
//        if (response != null) {
//            resLog = JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect);
//        }
//        asyncFlowLogDetailEntity.setRequest(reqLog);
//        asyncFlowLogDetailEntity.setResponse(resLog);
//        asyncFlowLogDetailEntity.setStatus(status);
//        asyncFlowNodeResponse.getAsyncFlowNodeDetailLogEntityList().add(asyncFlowLogDetailEntity);
//    }

    //endregion

    //region 执行完毕后保存节点执行日志

    /**
     * 执行完毕后保存节点执行日志
     *
     * @param request          请求参数
     * @param AsyncFlowContext 上下文
     * @param response         返回参数
     * @param timeConsuming    耗时详细
     */
    public static void SaveExecuteTrackLogs(Object request, AsyncFlowBaseContext AsyncFlowContext, Object response, LinkedHashMap<ExecuteEnum, Long> timeConsuming, boolean allNodeIsSuccess, AsyncFlowInfo asyncFlowInfo) {

        AsyncFlowRequest asyncFlowRequest = AsyncFlowContext.getAsyncFlowRequest(AsyncFlowRequest.class);
        //异步流配置不需要记录日志，直接跳出【只有线上环境才生效】
        if (AsyncFlowContext.getAsyncFlowInfo().getIgnoreFlowLogEvn().contains(AsyncFlowContext.getAsyncFlowInfo().getEvn()) ) {
            return;
        }
        boolean errorRequest = false;
        //总耗时和耗时明细组装
        String uptimeDes;
        long uptime = 0;
        StringBuilder stringBuilderUptimeDes = new StringBuilder();

        for (Map.Entry<ExecuteEnum, Long> entry : timeConsuming.entrySet()) {
            long time = entry.getValue();
            stringBuilderUptimeDes.append("【").append(entry.getKey().getMsg()).append("--").append(time).append("ms").append("】");
            uptime = uptime + time;
        }
        uptimeDes = "【总耗时--" + uptime + "ms】" + stringBuilderUptimeDes.toString();
        //保存流程运行轨迹
        AsyncFlowLogEntity asyncFlowLogEntity = new AsyncFlowLogEntity();
        try {
            //请求参数中没有给唯一号，自动生成一个默认的唯一号
            if (StringUtils.isBlank(asyncFlowRequest.getBusinessSerialId())) {
                errorRequest = true;
                String dateGuid = LocalDateTimeUtil.format(asyncFlowRequest.getRequesterTime(), DatePattern.PURE_DATETIME_PATTERN);
                asyncFlowLogEntity.setBusinessSerialId(asyncFlowRequest.getReqTypeEnumMsg() + "-" + dateGuid);
            } else {
                asyncFlowLogEntity.setBusinessSerialId(asyncFlowRequest.getBusinessSerialId());
            }

            asyncFlowLogEntity.setLogTime(LocalDateTimeUtil.format(asyncFlowRequest.getRequesterTime(), DatePattern.NORM_DATETIME_MS_PATTERN));
            asyncFlowLogEntity.setAsyncFlowModule(asyncFlowRequest.getReqTypeEnumName() + "-" + asyncFlowRequest.getReqTypeEnumMsg());
            asyncFlowLogEntity.setTrackGuid(UUID.randomUUID().toString().toLowerCase().replaceAll("-", ""));
            //asyncFlowLogEntity.setLogDateTime(request.getRequesterTime());
            asyncFlowLogEntity.setAsyncFlowDateTime(asyncFlowRequest.getRequesterTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());

            String resLog = "";
            if (response != null) {
                resLog = JSON.toJSONString(response, SerializerFeature.DisableCircularReferenceDetect);
            }
            asyncFlowLogEntity.setRequest(JSON.toJSONString(request, SerializerFeature.DisableCircularReferenceDetect));
            asyncFlowLogEntity.setResponse(resLog);
            asyncFlowLogEntity.setStatus(allNodeIsSuccess);
            asyncFlowLogEntity.setLogInfo(uptimeDes);
            asyncFlowLogEntity.setOperator(asyncFlowRequest.getOperateName() + "-" + asyncFlowRequest.getOperateNo());
            asyncFlowLogEntity.setSourceDes(asyncFlowRequest.getSourceDes());
            asyncFlowLogEntity.setUseTime(uptime);
            List<AsyncFlowNodeLogEntity> orderFlowLogs =
                    AsyncFlowContext.getAsyncFlowNodeLogEntityList().stream().sorted(Comparator.comparing(AsyncFlowNodeLogEntity::getLogTime)).collect(Collectors.toList());
            asyncFlowLogEntity.setAsyncFlowNodeLogEntityList(orderFlowLogs);

            String mongoDBConfig = asyncFlowInfo.getMongoDBConfigStr();

            //环境
            String evn = asyncFlowInfo.getEvn();
            asyncFlowLogEntity.setEnvironments(evn);
            //region 保存MongoDB
            MongoHelper<AsyncFlowLogEntity> mongoHelper;
            assert mongoDBConfig != null;
            if (mongoDBConfig.equals("close") || StringUtils.isEmpty(mongoDBConfig)) {
                return;
            } else {
                mongoHelper = new MongoHelper<>(mongoDBConfig, asyncFlowInfo.getMongoDBName(), asyncFlowInfo.getMongoDBTableName());
            }
            Document document = mongoHelper.toDocument(asyncFlowLogEntity);
            boolean result = mongoHelper.insertOne(document);
            mongoHelper.closeMongoClient();
            //endregion
            //region 发送超时报警
            if (asyncFlowInfo.getTimeOutsLimit() <= 0) {
                asyncFlowInfo.setTimeOutsLimit(6000);
            }

            if (StringUtils.isNotBlank(asyncFlowInfo.getFlowMaintainName()) && uptime > asyncFlowInfo.getTimeOutsLimit()) {
                String serialid = asyncFlowRequest.getBusinessSerialId();


                if (StringUtils.isBlank(serialid)) {
                    String dateGuid = LocalDateTimeUtil.format(asyncFlowRequest.getRequesterTime(), DatePattern.PURE_DATETIME_PATTERN);
                    ;
                    ;
                    serialid = asyncFlowRequest.getReqTypeEnumMsg() + "-" + dateGuid;
                }
                String stringBuilder = "【节点超时报警[" + asyncFlowInfo.getTimeOutsLimit() + "ms]】" +
                        "\n节点：" + asyncFlowRequest.getReqTypeEnumName() + "--" + asyncFlowRequest.getReqTypeEnumMsg() +
                        "\n来源：" + asyncFlowRequest.getSourceDes() +
                        "\n单号：" + serialid +
                        "\n时间：" + LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN) +
                        "\n环境：" + asyncFlowInfo.getEvn() +
                        "\n耗时：" + uptime +
                        "\n明细：" + uptimeDes;
                AsyncFlowSendMsg.sendQYWXMsg(asyncFlowInfo.getFlowMaintainName(), stringBuilder, asyncFlowInfo.getNodeArmUrl());
            }
            //endregion

            //异常请求，没有唯一标示
            if (errorRequest) {
                AsyncFlowSendMsg.sendAlarmMsg(asyncFlowRequest, "请求参数中唯一号BusinessSerialId为空", "SaveExecuteTrackLogs", AsyncFlowContext.getAsyncFlowInfo());
            }
        } catch (Exception e) {
            String msg = AsyncFlowSendMsg.buildErrorMsg(asyncFlowRequest, e, "SaveExecuteTrackLogs", asyncFlowInfo);
            AsyncFlowSendMsg.sendQYWXMsg(asyncFlowInfo.getFlowMaintainName(), msg, asyncFlowInfo.getNodeArmUrl());
        }


    }
    //endregion


}
